package com.dark.controller;

import com.dark.base.FlowerFallingErrorCodeEnmu;
import com.dark.base.Result;
import com.dark.util.AssertUtil;
import com.dark.util.JsonUtils;
import com.dark.util.RandomUtil;
import com.dark.util.StringUtils;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.dark.model.po.User;
import com.dark.service.IJCacheService;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * ClassName: BaseController
 * Description:BaseController
 *
 * @author chengluchao
 * @date: 2022/8/13 3:44 PM
 * @since 1.4.8
 */
@Slf4j
public class BaseController {

    private final static String TOKEN = "Token";

    @Resource
    protected HttpServletRequest request;
    @Resource
    protected HttpServletResponse response;

    @Resource
    IJCacheService cache;

    /**
     * 在线用户信息，单点部署*
     */
    private final static Cache<String, User> ONLINE_USER = CacheBuilder.newBuilder()
            .initialCapacity(2)
            .maximumSize(2000)
            .expireAfterWrite(7, TimeUnit.HOURS)
            .build();

    /**
     * 成功返回*
     *
     * @return 返回模板
     */
    protected static Result resultSuccess() {
        Result result = new Result<>(new HashMap<>());
        return result;
    }

    /**
     * 设置user token*
     *
     * @param token t
     * @param user  u
     */
    protected void settingToken(String token, User user) {
        // 使另一个过期，需要另一个缓存来做映射
        settingCookie(token);
        response.setHeader(TOKEN, token);
        ONLINE_USER.put(token, user);
    }

    private void settingCookie(String token) {
        // 创建Cookie对象
        Cookie cookie = new Cookie(TOKEN, token);
        cookie.setMaxAge(60 * 60 * 7);
        cookie.setPath("/");
        cookie.setDomain(request.getRemoteHost());
        // 将Cookie添加到响应中
        response.addCookie(cookie);

    }

    private static final String USER_INFO_PRE = "USER_INFO_";

    public User getUserInfo() {
        String token = getToken();
        // 本地缓存获取
        User user = ONLINE_USER.getIfPresent(token + "");
        if (user == null) {
            // 远程缓存获取数据
            String uString = cache.get(USER_KEY_PRR + token);
            if (!StringUtils.isEmpty(uString)) {
                user = JsonUtils.jsonStrToObject(uString, User.class);
                // 将远程缓存数据写入本地缓存
                if (user != null) {
                    ONLINE_USER.put(token, user);
                }
            }
        }
        AssertUtil.assertNouNull(user, FlowerFallingErrorCodeEnmu.LOGIN_INFORMATION_IS_INVALID);
        return user;
    }

    protected String getToken(User u) {
        String token = null;
        if (u == null) {
            return token;
        }
        // 查询分布式缓存
        token = getCacheByUser(u);
        if (token != null) {
            // token在有效期内，可以使用
            return token;
        }
        // default：：生成
        token = RandomUtil.string16() + RandomUtil.string16();
        cacheTokenByUser(u, token);
        return token;
    }

    private String getCacheByUser(User user) {
        return cache.get(getUserKey(user));
    }

    private void cacheTokenByUser(User user, String token) {
        String key = getUserKey(user);
        // 缓存一天
        cache.set(key, token, 1000 * 60 * 24);
        cache.set(USER_KEY_PRR + token, JsonUtils.toJSONString(user), 1000 * 60 * 24);
    }

    private static final String USER_KEY_PRR = "USER_TOKEN_";

    private static String getUserKey(User user) {
        return USER_INFO_PRE + user.getCode();
    }

    private String getToken() {
        // cookie中获取token
        Cookie[] cookies = request.getCookies();
        if (cookies != null && cookies.length > 0) {
            for (Cookie cookie : cookies) {
                String name = cookie.getName();
                String value = cookie.getValue();
                if (Objects.equals(name, TOKEN)) {
                    return value;
                }
            }
        }
        return request.getHeader(TOKEN);
    }
}
